/*
 * pidgin autostauts
 * Copyright (C) 2010
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02111-1301, USA.
 */

#include "autostatus.h"


static void cfg_dialog_st_select_menu_change_cb(PurpleSavedStatus *status)
{
    DEBUG("%s", purple_savedstatus_get_title(status));
}

static void cfg_dialog_close_cb(GtkObject *object, gpointer data)
{
    ConfigWindow *dialog = (ConfigWindow *) data; 
	g_free(dialog);
}

static void delete_network_rule_cb(GtkWidget *widget, gpointer data)
{
    ConfigWindow *dialog =  (ConfigWindow *)data;
    GtkTreeIter iter;
    GtkTreeSelection *selection;
    GList *sel_paths, *l = NULL;
	GtkTreeModel *model = GTK_LIST_STORE(gtk_tree_view_get_model(dialog->saved_network_rules_list));
    ConfigRule *rule = NULL;

    if (model == NULL)
        DEBUG("network treeview model is NULL");

    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->saved_network_rules_list ));
    sel_paths = gtk_tree_selection_get_selected_rows(selection, NULL);

    DEBUG("delete_network_rule_cb start");

    for (l = sel_paths; l != NULL; l = l->next) {
		if (gtk_tree_model_get_iter(model, &iter, l->data)) {
			gtk_tree_model_get(model, &iter, SAVED_CFG_DATA, &rule, -1);
            delete_rule(dialog->plugin, rule);
            gtk_list_store_remove(model, &iter);
		}
		gtk_tree_path_free(l->data);
	}
	g_list_free(sel_paths);

    DEBUG("delete_network_rule_cb end");
}


static void add_network_rule_cb(GtkWidget *widget, gpointer data)
{
    ConfigWindow *dialog =  (ConfigWindow *)data;
    GtkTreeIter iter;
    GtkTreeIter iter1;
    GtkTreeIter iter2;
    ConfigRule *rule;
    char *net_id;
    char *uuid;
    PurpleSavedStatus *status = NULL;
    int status_type;
    int status_key;

    gpointer status_data;
    GtkTreeModel *model = GTK_LIST_STORE(gtk_tree_view_get_model(dialog->saved_network_rules_list));
    

    if (!gtk_combo_box_get_active_iter(dialog->net_selector, &iter1))
		return;

    if (!gtk_combo_box_get_active_iter(dialog->status_selector_for_net, &iter2))
        return;

    gtk_tree_model_get(gtk_combo_box_get_model(dialog->net_selector), &iter1,
           NETWORK_CONNECT_ID, &net_id,
           NETWORK_CONNECT_UUID, &uuid,
           -1);


    gtk_tree_model_get(gtk_combo_box_get_model(dialog->status_selector_for_net), &iter2,
			   SS_MENU_TYPE_COLUMN, &status_type,
			   SS_MENU_DATA_COLUMN, &status_data,
			   -1);

    status_key = GPOINTER_TO_INT(status_data);

    if (status_type == SS_MENU_ENTRY_TYPE_PRIMITIVE)
	{
		PurpleStatusPrimitive primitive = GPOINTER_TO_INT(status_data);
		status = purple_savedstatus_find_transient_by_type_and_message(primitive, NULL);
		if (status == NULL)
			status = purple_savedstatus_new(NULL, primitive);
	}
	else if (status_type == SS_MENU_ENTRY_TYPE_SAVEDSTATUS)
		status = purple_savedstatus_find_by_creation_time(GPOINTER_TO_INT(status_data));

    char *status_title = purple_savedstatus_get_title(status); 
    DEBUG("status tilte:%s", status_title );
    DEBUG("net id:%s", net_id);

    if (( rule = add_network_rule(dialog->plugin, status_title, status_type, status_key, net_id, uuid) ) != NULL)
    {
        gtk_list_store_append (model, &iter);
        gtk_list_store_set (model, &iter,
                    SAVED_CFG_RULE, rule->name,
                    SAVED_CFG_DATA, (gpointer)rule,
                    -1);
        save_rules(dialog->plugin);
    }
    

    g_free(net_id);
    g_free(uuid);
}

static void show_error(ConfigWindow *dialog, char *msg)
{
    purple_notify_message(dialog->plugin->info, PURPLE_NOTIFY_MSG_ERROR,
						  "Error", msg, 
						  NULL, NULL,
						  NULL);
}

static void add_time_rule_cb(GtkWidget *widget, gpointer data)
{
    ConfigWindow *dialog =  (ConfigWindow *)data;
    GtkTreeIter iter;
    GtkTreeIter iter1;
    GtkTreeIter iter2;
    ConfigRule *rule;

    char *time_string;
    int time_hour;
    int time_min;
    int time_interval;

    PurpleSavedStatus *status = NULL;

    int status_type;
    int status_key;

    gpointer status_data;
    GtkTreeModel *model = gtk_tree_view_get_model(dialog->saved_time_rules_list);
    

    if (!gtk_combo_box_get_active_iter(dialog->time_interval_selector, &iter1))
		return;

    if (!gtk_combo_box_get_active_iter(dialog->status_selector_for_time, &iter2))
        return;
    
    //will not be free
    time_string = gtk_entry_get_text(dialog->time_selector);
    if (strlen(time_string) == 0)
    {
        show_error(dialog, "invalid time format"); 
        return;
    }
    
    if (sscanf(time_string, "%d:%d", &time_hour, &time_min) != 2)
    {
        show_error(dialog, "invalid time format"); 
        return; 
    }
    
    if (time_hour < 0 || time_hour > 24 || time_min < 0 || time_min > 59)
    {
        show_error(dialog, "invalid time format"); 
        return;  
    }

    DEBUG("get time:%d:%d", time_hour, time_min);

    gtk_tree_model_get(gtk_combo_box_get_model(dialog->time_interval_selector), &iter1,
           TIME_INTERVAL_VALUE, &time_interval,
           -1);

    DEBUG("interval type:%d", time_interval);

    gtk_tree_model_get(gtk_combo_box_get_model(dialog->status_selector_for_time), &iter2,
			   SS_MENU_TYPE_COLUMN, &status_type,
			   SS_MENU_DATA_COLUMN, &status_data,
			   -1);

    status_key = GPOINTER_TO_INT(status_data); 

    if (status_type == SS_MENU_ENTRY_TYPE_PRIMITIVE)
	{
		PurpleStatusPrimitive primitive = GPOINTER_TO_INT(status_data);
		status = purple_savedstatus_find_transient_by_type_and_message(primitive, NULL);
		if (status == NULL)
			status = purple_savedstatus_new(NULL, primitive);
	}
	else if (status_type == SS_MENU_ENTRY_TYPE_SAVEDSTATUS)
		status = purple_savedstatus_find_by_creation_time(GPOINTER_TO_INT(status_data));

    char *status_title = purple_savedstatus_get_title(status); 
    DEBUG("status tilte:%s", status_title );

    if (( rule = add_time_rule(dialog->plugin, status_title, status_type, status_key, time_string, time_interval) ) != NULL)
    {
        gtk_list_store_append (model, &iter);
        gtk_list_store_set (model, &iter,
                    SAVED_CFG_RULE, rule->name,
                    SAVED_CFG_DATA, (gpointer)rule,
                    -1);
        save_rules(dialog->plugin);
    }
    
}

static void delete_time_rule_cb(GtkWidget *widget, gpointer data)
{
    ConfigWindow *dialog =  (ConfigWindow *)data;
    GtkTreeIter iter;
    GtkTreeSelection *selection;
    GList *sel_paths, *l = NULL;
	GtkTreeModel *model = GTK_LIST_STORE(gtk_tree_view_get_model(dialog->saved_time_rules_list));
    ConfigRule *rule = NULL;

    if (model == NULL)
        DEBUG("time treeview model is NULL");

    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->saved_time_rules_list ));
    sel_paths = gtk_tree_selection_get_selected_rows(selection, NULL);

    DEBUG("delete_time_rule_cb start");

    for (l = sel_paths; l != NULL; l = l->next) {
		if (gtk_tree_model_get_iter(model, &iter, l->data)) {
			gtk_tree_model_get(model, &iter, SAVED_CFG_DATA, &rule, -1);
            delete_rule(dialog->plugin, rule);
            gtk_list_store_remove(model, &iter);
		}
		gtk_tree_path_free(l->data);
	}
	g_list_free(sel_paths);

    DEBUG("delete_time_rule_cb end");
}

static GtkWidget *
get_config_frame(PurplePlugin *plugin)
{
	GtkWidget *frame;
    GtkWidget *page;
	ConfigWindow *dialog;
	GtkWidget *group;
	GtkWidget *label;
	GtkWidget *hbox;
	GtkWidget *button;
	GtkWidget *st_select_menu;
    GtkWidget *nw_select_menu;
    GtkWidget *tm_select_menu;
    GtkWidget *tmit_select_menu;
    GtkWidget *saved_cfg_list;
    AutoStatus *plg = (AutoStatus *)plugin->extra;
	dialog = g_new0(ConfigWindow, 1);
    dialog->plugin = plg;

    frame = gtk_notebook_new();
    
    label = gtk_label_new("network setting");
	page = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
    gtk_notebook_append_page(GTK_NOTEBOOK(frame), page, label);
	gtk_container_set_border_width(GTK_CONTAINER(page), PIDGIN_HIG_BORDER);


    hbox = gtk_hbox_new(FALSE, 0);
    gtk_box_set_spacing(GTK_BOX(hbox),5);

    gtk_box_pack_start(GTK_BOX(page), hbox, TRUE, TRUE, 0);

    label = gtk_label_new("Change to");
    gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);

    st_select_menu = pidgin_status_menu(NULL, G_CALLBACK(cfg_dialog_st_select_menu_change_cb));
    dialog->status_selector_for_net = st_select_menu;
    gtk_widget_set_size_request(st_select_menu, 150, -1);
    gtk_box_pack_start(GTK_BOX(hbox), st_select_menu, TRUE, TRUE, 0);

    label = gtk_label_new("when");
    gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);

    nw_select_menu = network_select_menu_new();
    dialog->net_selector = nw_select_menu;
    gtk_widget_set_size_request(nw_select_menu, 150, -1);
    gtk_box_pack_start(GTK_BOX(hbox), nw_select_menu, TRUE, TRUE, 0);

    label = gtk_label_new("connected");
    gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);

    group = gtk_hbutton_box_new();
    gtk_button_box_set_layout(GTK_BUTTON_BOX(group),GTK_BUTTONBOX_END);
    gtk_box_pack_start(GTK_BOX(page), group, TRUE, TRUE, 0);

    button = gtk_button_new_with_label("Add rule");
    //gtk_widget_set_size_request(button, 150, -1);
    gtk_box_pack_start(GTK_BOX(group), button, TRUE, TRUE, 0);
    g_signal_connect (button, "clicked", G_CALLBACK (add_network_rule_cb), dialog);

    saved_cfg_list = saved_network_rules_list_new(dialog);
    gtk_widget_set_size_request(saved_cfg_list, -1, 200);
    gtk_box_pack_start(GTK_BOX(page), saved_cfg_list, TRUE, TRUE, 0);

    group = gtk_hbutton_box_new();
    gtk_button_box_set_layout(GTK_BUTTON_BOX(group),GTK_BUTTONBOX_END);
    gtk_box_pack_start(GTK_BOX(page), group, TRUE, TRUE, 0);

    button = gtk_button_new_with_label("Delete rule");
    //gtk_widget_set_size_request(button, 150, -1);
    gtk_box_pack_start(GTK_BOX(group), button, TRUE, TRUE, 0);
    g_signal_connect (button, "clicked", G_CALLBACK (delete_network_rule_cb), dialog);


    label = gtk_label_new("time setting");
	page = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
    gtk_notebook_append_page(GTK_NOTEBOOK(frame), page, label);
	gtk_container_set_border_width(GTK_CONTAINER(page), PIDGIN_HIG_BORDER);

    hbox = gtk_hbox_new(FALSE, 0);
    //gtk_box_set_spacing(GTK_BOX(hbox),5);
    gtk_box_pack_start(GTK_BOX(page), hbox, TRUE, TRUE, 0);

    label = gtk_label_new("Change to");
    gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);

    st_select_menu = pidgin_status_menu(NULL, G_CALLBACK(cfg_dialog_st_select_menu_change_cb));
    dialog->status_selector_for_time = st_select_menu;
    gtk_widget_set_size_request(st_select_menu, 100, -1);
    gtk_box_pack_start(GTK_BOX(hbox), st_select_menu, TRUE, TRUE, 0);

    label = gtk_label_new("on");
    gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);

    tm_select_menu = time_select_menu_new();
    gtk_widget_set_size_request(tm_select_menu, 80, -1);
    dialog->time_selector = tm_select_menu;
    gtk_box_pack_start(GTK_BOX(hbox), tm_select_menu, TRUE, TRUE, 0);

    label = gtk_label_new("every");
    gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
    
    tmit_select_menu = time_interval_select_menu_new();
    dialog->time_interval_selector = tmit_select_menu;
    gtk_box_pack_start(GTK_BOX(hbox), tmit_select_menu, TRUE, TRUE, 0);

    group = gtk_hbutton_box_new();
    gtk_button_box_set_layout(GTK_BUTTON_BOX(group),GTK_BUTTONBOX_END);
    gtk_box_pack_start(GTK_BOX(page), group, TRUE, TRUE, 0);

    button = gtk_button_new_with_label("Add rule");
    //gtk_widget_set_size_request(button, 150, -1);
    gtk_box_pack_start(GTK_BOX(group), button, TRUE, TRUE, 0);
    g_signal_connect (button, "clicked", G_CALLBACK (add_time_rule_cb), dialog);
    
    saved_cfg_list = saved_time_rules_list_new(dialog);
    gtk_widget_set_size_request(saved_cfg_list, -1, 200);
    gtk_box_pack_start(GTK_BOX(page), saved_cfg_list, TRUE, TRUE, 0);

    group = gtk_hbutton_box_new();
    gtk_button_box_set_layout(GTK_BUTTON_BOX(group),GTK_BUTTONBOX_END);
    gtk_box_pack_start(GTK_BOX(page), group, TRUE, TRUE, 0);

    button = gtk_button_new_with_label("Delete rule");
    //gtk_widget_set_size_request(button, 150, -1);
    gtk_box_pack_start(GTK_BOX(group), button, TRUE, TRUE, 0);
    g_signal_connect (button, "clicked", G_CALLBACK (delete_time_rule_cb), dialog);

	g_signal_connect(GTK_OBJECT(frame), "destroy", G_CALLBACK(cfg_dialog_close_cb), dialog);

	gtk_widget_show_all(frame);
	return frame;
}


static void
network_changed_callback (DBusGProxy *proxy,
                          GHashTable *properties,
                          gpointer user_data)
{
    AutoStatus *plg = (AutoStatus *)user_data;
    network_connection_t *connection = get_active_network_connections(plg->dbus);

    if (connection == NULL)
        DEBUG("no actived connections");
    else
        DEBUG("active connections:%s", connection->id);
    
    if (connection != NULL)
    {
        network_connection_t *_tmp_con = connection;
        while(_tmp_con != NULL)
        {
            DEBUG("test active connection:%s", _tmp_con->id);
            //说明是一个新的连接
            if (is_network_connection_active(plg, _tmp_con) == -1)
            {
                DEBUG("%s is new connected", _tmp_con->id);
                //更改成功跳出循环
                if (active_status_by_network(plg, _tmp_con) == 0)
                    break;
            }
            _tmp_con = _tmp_con->next;
        }
    }

    network_connections_free(plg->active_connections );
    plg->active_connections = connection;
}

static gboolean time_check_cb(gpointer data)
{
    AutoStatus *plg = (AutoStatus *)data;
    active_status_by_time(plg);
    return TRUE;
}

static gboolean
plugin_load(PurplePlugin *plugin)
{
    DEBUG("load start");
    AutoStatus *plg = (AutoStatus *)calloc(1, sizeof(AutoStatus));
    plg->rules = NULL;
    plg->info = plugin;
    plugin->extra = (void *)plg;
    network_connection_t *_tmp_con;
    
    load_rules(plg);

    plg->dbus = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);

    _tmp_con = plg->active_connections = get_active_network_connections(plg->dbus);


    while(_tmp_con != NULL)
    {
        DEBUG("active connection init:%s", _tmp_con->id);
        if (active_status_by_network(plg, _tmp_con) == 0)
            break;
        _tmp_con = _tmp_con->next;
    }

    plg->nm_proxy = dbus_g_proxy_new_for_name(plg->dbus,
		                                     NM_DBUS_SERVICE,
		                                     NM_DBUS_PATH,
		                                     NM_DBUS_INTERFACE);
    dbus_g_proxy_add_signal (plg->nm_proxy, "PropertiesChanged", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
    dbus_g_proxy_connect_signal (plg->nm_proxy,
                                            "PropertiesChanged",
                                            G_CALLBACK (network_changed_callback),
                                            (void *)plg,
                                            NULL);

    plg->check_timer = purple_timeout_add_seconds(TIMEOUT_CHECK_INTERVAL, (GSourceFunc)time_check_cb, plg);


	return TRUE;
}

static gboolean
plugin_unload(PurplePlugin *plugin)
{
    DEBUG("unload start");
    AutoStatus *plg = (AutoStatus *)plugin->extra; 
    config_rules_free(plg->rules);
    dbus_g_proxy_disconnect_signal(plg->nm_proxy, "PropertiesChanged",
                                            G_CALLBACK (network_changed_callback),
                                            NULL);
    g_object_unref (plg->nm_proxy);
    dbus_g_connection_unref (plg->dbus);
    network_connections_free(plg->active_connections);
    purple_timeout_remove(plg->check_timer);
    g_free(plg);
	return TRUE;
}

static gboolean
plugin_destroy(PurplePlugin *plugin)
{
    DEBUG("destroy start");
    
    return TRUE;
}

static PidginPluginUiInfo ui_info = 
{
	get_config_frame,
	0,

	/* padding */
	NULL,
	NULL,
	NULL,
	NULL
};

static PurplePluginInfo info =
{
	PURPLE_PLUGIN_MAGIC,            /* Magic              */
	PURPLE_MAJOR_VERSION,           /* Purple Major Version */
	PURPLE_MINOR_VERSION,           /* Purple Minor Version */
	PURPLE_PLUGIN_STANDARD,         /* plugin type        */
	PIDGIN_PLUGIN_TYPE,         /* ui requirement     */
	0,                            /* flags              */
	NULL,                         /* dependencies       */
	PURPLE_PRIORITY_DEFAULT,        /* priority           */

	PLUGIN_ID,                    /* plugin id          */
	PLUGIN_NAME,                  /* name               */
	DISPLAY_VERSION,              /* version            */
	PLUGIN_SUMMARY,               /* summary            */
	PLUGIN_DESCRIPTION,           /* description        */
	PLUGIN_AUTHOR,                /* author             */
	PURPLE_WEBSITE,                 /* website            */

	plugin_load,                  /* load               */
	plugin_unload,                /* unload             */
	plugin_destroy,                /* destroy            */

	&ui_info,                     /* ui_info            */
	NULL,                         /* extra_info         */
	NULL,                         /* prefs_info         */
	NULL,                         /* actions            */

	/* padding */
	NULL,
	NULL,
	NULL,
	NULL
};

static void
init_plugin(PurplePlugin *plugin)
{
    purple_prefs_add_none(PREF_PREFIX);
    purple_prefs_add_string_list(PREF_CFG_SAVED_RULE, NULL);
}

PURPLE_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)
